package net.csdn.business.auth.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import net.csdn.business.auth.component.CustomAuthExceptionEntryPoint;
import net.csdn.business.auth.component.CustomAuthorizationCodeServices;
import net.csdn.business.auth.component.CustomAuthorizationServerTokenServices;
import net.csdn.business.common.oauth2.component.CustomRedisTokenStore;
import net.csdn.business.common.oauth2.service.IOauthCodeService;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;

import java.util.Arrays;


/**
 * @Desc: 认证服务器配置
 * @ClassName: AuthorizationServerConfig
 * @Author: yourleige@163.com
 * @Date: 2022/9/27 10:35
 */
@Configuration
@AutoConfigureBefore(CustomOath2Config.class)
@AllArgsConstructor
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

	private final ClientDetailsService customClientDetailsService;

	private final AuthenticationManager authenticationManagerBean;

	private final UserDetailsService customUserDetailsService;

	private final IOauthCodeService oauthCodeService;

	private final CustomRedisTokenStore customRedisTokenStore;

	//private final CustomWebResponseExceptionTranslator exceptionTranslator;

	//private final BCryptPasswordEncoder passwordEncoder;//密码加密方式

	private final ObjectMapper objectMapper;


	@Bean
	public AuthorizationCodeServices authorizationCodeServices() {
		//加入对授权码模式的支持
		return new CustomAuthorizationCodeServices(oauthCodeService);
	}

	@Bean
	@Primary
	public CustomAuthorizationServerTokenServices authorizationServerTokenServices(){
		CustomAuthorizationServerTokenServices tokenServices=new CustomAuthorizationServerTokenServices();
		tokenServices.setTokenStore(customRedisTokenStore);
		tokenServices.setSupportRefreshToken(true);
		tokenServices.setReuseRefreshToken(true);
		tokenServices.setClientDetailsService(customClientDetailsService);
		addUserDetailsService(tokenServices,customUserDetailsService);
		return tokenServices;
	}

	private void addUserDetailsService(CustomAuthorizationServerTokenServices tokenServices, UserDetailsService userDetailsService) {
		if (userDetailsService != null) {
			PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
			provider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken>(
					userDetailsService));
			tokenServices
					.setAuthenticationManager(new ProviderManager(Arrays.<AuthenticationProvider> asList(provider)));
		}
	}



	@Override
	@SneakyThrows
	public void configure(ClientDetailsServiceConfigurer clients) {
		clients.withClientDetails(customClientDetailsService);
	}

	@Override
	public void configure(AuthorizationServerSecurityConfigurer security) {
		security.allowFormAuthenticationForClients()
				//.passwordEncoder(passwordEncoder)   // 配置BCrypt加密
				.authenticationEntryPoint(new CustomAuthExceptionEntryPoint(objectMapper))
				.checkTokenAccess("isAuthenticated()");
	}

	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
		endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST).tokenStore(customRedisTokenStore)
				.userDetailsService(customUserDetailsService)
				.authorizationCodeServices(authorizationCodeServices())
				.authenticationManager(authenticationManagerBean)
				//自定义的AuthorizationServerTokenServices
				.tokenServices(authorizationServerTokenServices())
				.reuseRefreshTokens(true)
				.pathMapping("/oauth/confirm_access", "/oauth/confirm")
				//.exceptionTranslator(exceptionTranslator)
		;
	}

}
